package com.tanhua.manage.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.tanhua.manage.pojo.User;
import com.tanhua.manage.enums.LogTypeEnum;
import com.tanhua.manage.pojo.AnalysisByDay;
import com.tanhua.manage.pojo.Log;
import com.tanhua.manage.vo.RetentionVo;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author zps
 * @date 2021/3/29
 * @TIME:16:34
 */
@Service
@Slf4j
public class RegisteredService {
    @Autowired
    private AnalysisService analysisService;
    @Autowired
    private LogService logService;
    @Autowired
    private UserService userService;

    public ArrayList<RetentionVo> retention(DateTime startDay,DateTime endDay){
        //把startDay和endDay再转为Long类型
        //endDay与startDay相差天数days
        Long days = DateUtil.betweenDay( startDay, endDay, true);
        ArrayList<RetentionVo>  list = new ArrayList<>();
        for (Long i = 1L; i <=days +1 ; i++) {
            //求startDay,startDay的明天,startDay的后天.....
            RetentionVo retentionVo =this.getRetention(DateUtil.offsetDay(startDay,Integer.parseInt(String.valueOf(i))).toDateStr());
            list.add(retentionVo);
        }
       return list;
    }


    private RetentionVo getRetention(String todayStr) {
       Date today = DateUtil.parse(todayStr);

        AnalysisByDay analysisByDay = this.analysisService.getOne(Wrappers.<AnalysisByDay>lambdaQuery()
                .eq(AnalysisByDay::getRecordDate, today));//查询一下传入的当天在tb_analysis_by_day中有没有数据
        if (null == analysisByDay) {
            //当天还没有统计数据,创建
            analysisByDay = new AnalysisByDay();
            analysisByDay.setRecordDate(DateUtil.parseDate(todayStr));
            this.analysisService.save(analysisByDay);
        }
        //查询用户登录数据
        List<Log> logList = this.logService.list(Wrappers.query(Log.builder()
                .logTime(todayStr)
                .type(LogTypeEnum.LOGIN.getValue())
                .build()).select("DISTINCT(user_id)")
        );
        //统计数据归0，重新计算
        analysisByDay.setNumRegistered(0);
        analysisByDay.setNumRetention1d(0);
        Integer numDay2 = 0;  //2天后留存数
        Integer numDay3 = 0;  //3天后留存数
        Integer numDay4 = 0;  //4天后留存数
        Integer numDay5 = 0;  //5天后留存数
        Integer numDay6 = 0;  //6天后留存数
        Integer numDay7 = 0;  //7天后留存数
        Integer numDay30 = 0;  //30天后留存数
        if (CollUtil.isNotEmpty(logList)) {
            //今日登录用户
            // analysisByDay.setNumLogin(logList.size());
            ArrayList<User> userArrayList = new ArrayList<>();
            //根据登录的用户数据查询用户
            List<User> userList = this.userService.list(Wrappers.<User>lambdaQuery().in(User::getId, CollUtil.getFieldValues(logList, "userId")));
            for (User user : userList) {
                //查询用户的创建时间;    当天的时间-用户注册的时间
                Long days = DateUtil.betweenDay((Date) user.getCreated(), today, true);//today=2020.8.10
                if (days == 0) {
                    //今日注册的用户集合及用户数
                    userArrayList.add(user);
                    analysisByDay.setNumRegistered(analysisByDay.getNumRegistered() + 1);
                }
            }
            //统计(today+1)天用户登录数即为留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 1).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    analysisByDay.setNumRetention1d(analysisByDay.getNumRetention1d() + 1);
                }
            }
            //(today+2)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 2).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay2++;
                }
            }
            //(today+3)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 3).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay3++;
                }
            }
            //(today+4)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 4).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay4++;
                }
            }
            //(today+5)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 5).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay5++;
                }
            }
            //(today+6)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 6).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay6++;
                }
            }
            //(today+7)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 7).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay7++;
                }
            }
            //(today+30)天的留存数
            for (User user : userArrayList) {
                Log log = logService.getOne(Wrappers.query(Log.builder()
                        .logTime(DateUtil.offsetDay(today, 30).toString())
                        .userId(user.getId())
                        .type(LogTypeEnum.LOGIN.getValue())
                        .build())
                );
                if (log!=null){
                    numDay30++;
                }
            }
        }
        //次日留存率 = 次日留存数/新注册用户数
        Integer result=0;
        if (analysisByDay.getNumRegistered()==0){
            result=0;
        }else{
            result= analysisByDay.getNumRetention1d() / analysisByDay.getNumRegistered();
        }

        NumberFormat num = NumberFormat.getPercentInstance();
        num.setMaximumFractionDigits(2);
        String oneDay = num.format(result.doubleValue());
        //2天后留存率
        Integer result2=0;
        if (analysisByDay.getNumRegistered()==0){
            result2=0;
        }else {
            result2= numDay2 / analysisByDay.getNumRegistered();
        }
        String towDay = num.format(result2.doubleValue());
        //3天后留存率
        Integer result3=0;
        if (analysisByDay.getNumRegistered()==0){
            result3=0;
        }else {

            result3= numDay3 / analysisByDay.getNumRegistered();
        }
        String threeDay = num.format(result3.doubleValue());
        //4天后留存率
        Integer result4=0;
        if (analysisByDay.getNumRegistered()==0){
            result4=0;
        }else {

            result4= numDay4 / analysisByDay.getNumRegistered();
        }
        String fourDay = num.format(result4.doubleValue());
        //5天后留存率
        Integer result5=0;
        if (analysisByDay.getNumRegistered()==0){
            result5=0;
        }else {

            result5= numDay5 / analysisByDay.getNumRegistered();
        }
        String fiveDay = num.format(result5.doubleValue());
        //6天后留存率
        Integer result6=0;
        if (analysisByDay.getNumRegistered()==0){
            result6=0;
        }else {

            result6= numDay6 / analysisByDay.getNumRegistered();
        }
        String sixDay = num.format(result6.doubleValue());
        //7天后留存率
        Integer result7=0;
        if (analysisByDay.getNumRegistered()==0){
            result7=0;
        }else {

            result7= numDay7 / analysisByDay.getNumRegistered();
        }
        String sevenDay = num.format(result7.doubleValue());
        //30天后留存率
        Integer result30=0;
        if (analysisByDay.getNumRegistered()==0){
            result30=0;
        }else {

            result30= numDay30 / analysisByDay.getNumRegistered();
        }

        String thirtyDay = num.format(result30.doubleValue());

        //用户注册数
        Integer registeredNum = analysisByDay.getNumRegistered();
        //存入vo对象中
        RetentionVo retentionVo = new RetentionVo();
        retentionVo.setTime(today);
        retentionVo.setRegisteredNum(registeredNum);
        retentionVo.setOneDay(oneDay);
        retentionVo.setTowDay(towDay);
        retentionVo.setThreeDay(threeDay);
        retentionVo.setFourDay(fourDay);
        retentionVo.setFiveDay(fiveDay);
        retentionVo.setSixDay(sixDay);
        retentionVo.setSevenDay(sevenDay);
        retentionVo.setThirtyDay(thirtyDay);

        return retentionVo;
    }


}
